<template>
  <div :class="prefixCls">
    <el-upload class="avatar-uploader" :action="define.comUploadUrl+'/'+imgType" :show-file-list="false"
      :on-success="uploadSuccess" :before-upload="beforeUpload" :headers="uploadHeaders" v-show="false"> </el-upload>
    <quill-editor v-model="content" ref="QuillEditor" :content="value" :options="editorOption"
      @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @ready="onEditorReady($event)"
      @change="onEditorChange($event)">
    </quill-editor>

    <!-- 图片预览对话框：点击编辑器中的图片时打开预览，支持等比显示（北京时间：2025-11-13） -->
    <el-dialog :visible.sync="previewVisible" width="60%" append-to-body>
      <img :src="previewSrc" alt="preview" class="preview-img" />
      <span slot="title">图片预览</span>
    </el-dialog>
  </div>
</template>

<script>
const units = {
  KB: 1024,
  MB: 1024 * 1024,
  GB: 1024 * 1024 * 1024
}
import { quillEditor } from 'vue-quill-editor'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'

export default {
  name: 'Quill',
  components: { quillEditor },
  props: {
    prefixCls: {
      type: String,
      default: 'cu-editor-quill'
    },
    // 表单校验用字段
    // eslint-disable-next-line
    value: {
      type: String
    },
    placeholder: {
      type: String,
      default: '请输入内容...'
    },
    imgType: {
      type: String,
      default: 'Quill'
    },
    sizeUnit: {
      type: String,
      default: 'MB'
    },
    fileSize: {
      default: 5
    },
  },
  data () {
    return {
      uploadHeaders: { Authorization: this.$store.getters.token },
      content: this.value,
      // 图片预览状态（北京时间：2025-11-13）
      previewVisible: false,
      previewSrc: '',
      editorOption: {
        modules: {
          history: {
            delay: 1000,
            maxStack: 50,
            userOnly: false
          },
          toolbar: {
            container: [
              ["bold", "italic", "underline", "strike"],
              [{ header: [1, 2, 3, 4, 5, 6, false] }],
              [{ size: ["small", false, "large", "huge"] }],
              [{ color: [] }, { background: [] }],
              ["blockquote", "code-block"],
              [{ list: "ordered" }, { list: "bullet" }],
              [{ indent: "-1" }, { indent: "+1" }],
              [{ align: [] }],
              [{ direction: "rtl" }],
              ["clean"],
              ["link", "image"],
            ],
            handlers: {
              image: function (value) {
                if (value) {
                  // 调用element的图片上传组件
                  document.querySelector('.avatar-uploader input').click()
                } else {
                  this.quill.format('image', false)
                }
              }
            }
          }
        },
        theme: 'snow',
        placeholder: this.placeholder
      }
    }
  },
  methods: {
    /**
     * 图片点击事件处理：当用户点击编辑器中的图片时，打开预览对话框
     * 说明：通过事件委托监听 .ql-editor 内的 img 元素，提取 src 进行预览
     * 日期：北京时间 2025-11-13
     */
    onEditorImageClick (evt) {
      const target = evt.target
      if (target && target.tagName === 'IMG' && target.src) {
        this.previewSrc = target.src
        this.previewVisible = true
      }
    },
    /**
     * 绑定图片预览事件：在编辑器就绪后为内容根节点绑定图片点击处理
     * 日期：北京时间 2025-11-13
     */
    bindImagePreview () {
      const root = this.$refs.QuillEditor && this.$refs.QuillEditor.quill && this.$refs.QuillEditor.quill.root
      if (root) {
        root.addEventListener('click', this.onEditorImageClick)
      }
    },
    /**
     * 解绑图片预览事件：在组件销毁前移除绑定的事件，避免内存泄漏
     * 日期：北京时间 2025-11-13
     */
    unbindImagePreview () {
      const root = this.$refs.QuillEditor && this.$refs.QuillEditor.quill && this.$refs.QuillEditor.quill.root
      if (root) {
        root.removeEventListener('click', this.onEditorImageClick)
      }
    },
    onEditorBlur (quill) {
      // console.log('editor blur!', quill)
    },
    onEditorFocus (quill) {
      // console.log('editor focus!', quill)
    },
    onEditorReady (quill) {
      // console.log('editor ready!', quill)
      // 绑定图片预览事件（北京时间：2025-11-13）
      this.bindImagePreview()
    },
    onEditorChange ({ quill, html, text }) {
      // console.log('editor change!', quill, html, text)
      // this.$emit('change', html)
      this.$emit("input", this.content);
    },
    beforeUpload (file) {
      const unitNum = units[this.sizeUnit];
      if (!this.fileSize) return true
      let isRightSize = file.size / unitNum < this.fileSize
      if (!isRightSize) {
        this.$message.error(`文件大小超过${this.fileSize}${this.sizeUnit}`)
      }
      // let isAccept = new RegExp(this.accept).test(file.type)
      // if (!isAccept) {
      //   this.$message.error(`应该选择${this.accept}类型的文件`)
      // }
      return isRightSize;
    },
    uploadSuccess (res) {
      // 获取富文本组件实例
      let quill = this.$refs.QuillEditor.quill
      // 如果上传成功
      if (res) {
        // 获取光标所在位置
        let length = quill.getSelection().index;
        // 插入图片，res为服务器返回的图片链接地址
        quill.insertEmbed(length, 'image', res.data.url)
        // 调整光标到最后
        quill.setSelection(length + 1)
      } else {
        // 提示信息，需引入Message
        this.$message.error('图片插入失败！')
      }
    }
  },
  computed: {
    editor () {
      return this.$refs.CustomQuillEditor.quill
    }
  },
  mounted () {
    // 保底绑定：若编辑器就绪事件未触发或过早触发，mounted 中再尝试绑定（北京时间：2025-11-13）
    this.bindImagePreview()
  },
  beforeDestroy () {
    // 解绑事件，避免内存泄漏（北京时间：2025-11-13）
    this.unbindImagePreview()
  },
  watch: {
    value (val) {
      this.content = val
    },
    placeholder (val) {
      this.$set(this.editorOption, 'placeholder', val)
    }
  }
}
</script>
<style lang="scss" scoped>
.cu-editor-quill {
  >>> .ql-editor {
    min-height: 400px;
  }
  >>> .ql-editor img {
    max-width: 100%;
    height: auto;
    display: block;
    max-height: 360px;
    margin: 8px 0;
  }
  >>> .ql-toolbar.ql-snow {
    border: 1px solid #dcdfe6;
    border-bottom: 0;
    border-radius: 4px 4px 0 0;
  }
  >>> .ql-container.ql-snow {
    border: 1px solid #dcdfe6;
    border-radius: 0 0 4px 4px;
  }
}
.preview-img {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
}
</style>
